/*
 * @(#)DeneubourgAnt.java			0.1 04/12/2010
 * Copyright (C) 2010 Grupo de Alunos abaixo
 * 
 * Universidade Federal do ABC
 * Vida Artificial - 3o quadrimestre de 2010
 * Aluno: Abner
 * Aluno: Cláudio Antônio Peanho
 * Aluno: Fabrizio Borelli
 * Aluna: Maitê Balhester
 * Aluno: Rafael Munhoz
 * Professora Dr. Karla Vittori
 * Projeto: Simulação de Colônia de Formigas (antcolonyswarm)
 * 
 * Código baseado em jheatbugs-3.0 de Timothy Howe
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package br.edu.ufabc.va.acs.model.agent;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import br.edu.ufabc.va.acs.model.AntWorld;
import swarm.Globals;
import swarm.gui.Raster;

/**
 * @author Peanho
 * 
 */
public class DeneubourgAnt implements Ant {

	/** mundo da simulação */
	private final AntWorld				world;

	/** coordenadas da colonia na grade bidimensional */
	private final Point					colonyPos;

	/** indice no mapa de cores */
	private byte						colorIndex;

	/** posição atual da formiga na grade bidimensional */
	private Point						pos;

	/** indica se a formiga está procurando comida ou retornando a colônia */
	private boolean						searchingFood	= true;

	private final int					width;
	private final int					height;

	private final int					k				= 20;

	private final int					a				= 2;

	private static final List<Point>	offsetList		= Arrays.asList(
																new Point(-1,
																		-1),
																new Point(0, -1),
																new Point(1, -1),
																new Point(-1, 0),
																new Point(1, 0),
																new Point(-1, 1),
																new Point(0, 1),
																new Point(1, 1));

	/**
	 * 
	 * @param world
	 * @param colonyPos
	 */
	public DeneubourgAnt(AntWorld world, Point colonyPos) {
		this.world = world;
		width = world.getWidth();
		height = world.getHeight();
		this.colonyPos = colonyPos;
		this.pos = new Point(colonyPos);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * br.edu.ufabc.va.acs.controller.GraphicObject#drawSelfOn(swarm.gui.Raster)
	 */
	@Override
	public Object drawSelfOn(Raster raster) {
		raster.drawPointX$Y$Color(pos.x, pos.y, colorIndex);
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.edu.ufabc.va.acs.controller.GraphicObject#setColorIndex(byte)
	 */
	@Override
	public void setColorIndex(byte colorIndex) {
		this.colorIndex = colorIndex;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.edu.ufabc.va.acs.model.agent.Ant#move()
	 */
	@Override
	public synchronized void move() {
		Point to = new Point(pos);
		if (searchingFood) {
			List<Point> directionList = new ArrayList<Point>(offsetList.size());
			double sum = 0.0;
			double p = 0.0;
			/*
			 * Calcula a soma das intensidades de feromônio na vizinhança oito
			 * conectado descantando posições cheias
			 */
			for (Point offset : offsetList) {
				Point nextPos = new Point(pos);
				nextPos.translate(offset.x, offset.y);
				double pheromoneIntensity = 0;
				if (world.isValidPos(nextPos)) {
					pheromoneIntensity = k + world.getPheromoneValueAt(nextPos);
					sum += Math.pow(pheromoneIntensity, a);
					directionList.add(nextPos);
				}
			}
			for (Point neighbor : directionList) {
				double temp = k + world.getPheromoneValueAt(neighbor);
				double probability = Math.pow(temp, a) / sum;
				if (probability > p) {
					p = probability;
					to = neighbor;
				}
			}
			// realiza sorteio para aplicar a probalidade da formiga se mover para o ponto to
			double randomMoveProb = Globals.env.uniformDblRand
					.getDoubleWithMin$withMax(0.0, 1.0);
			if (randomMoveProb > p) {
				int index = Globals.env.uniformIntRand.getIntegerWithMin$withMax(0, directionList.size()-1);
				to = directionList.get(index);
			}
			
			if (world.isPositionEmpty(to)) {
				world.move(this, pos, to);
				pos.setLocation(to);
			}

			if (world.isFood(pos)) {
				searchingFood = false;
				colorIndex = (byte) 202;
				world.depositOnePheromoneUnit(pos);
			}
		} else {
			int dx = (colonyPos.x - pos.x);
			int dy = colonyPos.y - pos.y;
			if (dx != 0)
				dx = dx < 0 ? -1 : 1;
			if (dy != 0)
				dy = dy < 0 ? -1 : 1;
			int newX = pos.x + dx;
			int newY = pos.y + dy;
			if (colonyPos.x == newX && colonyPos.y == newY) {
				searchingFood = true;
				colorIndex = (byte) 201;
			} else {
				Point p = new Point(newX, newY);
				world.move(this, pos, p);
				world.depositOnePheromoneUnit(pos);
				pos.move(p.x, p.y);
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see br.edu.ufabc.va.acs.model.agent.Ant#setInitialPosition(int, int)
	 */
	@Override
	public void setInitialPosition(int x, int y) {
		this.pos = new Point(x, y);
	}

}
